home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 23
/
Amiga Format AFCD23 (Feb 1998, Issue 107).iso
/
-in_the_mag-
/
emulation
/
cpu
/
z80
/
z80.h
< prev
next >
Wrap
C/C++ Source or Header
|
1997-12-12
|
13KB
|
388 lines
#ifndef Z80_H
#define Z80_H
/*
* C header file for the Z80 emulator.
*
* All (or most) of these types have to be defined (and to the correct
* sizes): BYTE, UBYTE, WORD, UWORD, LONG and ULONG.
*
* If Z80_ENVDATA is defined, the last element of struct Z80_Control will
* be a structure named Envdata, of the type "struct Z80_Envdata", which
* you also must have defined.
*
*/
/* All sizes and offsets are in bytes: */
/* The amount of bytes needed for the Z80 memory space */
#define Z80_MEMSIZE 0x10000
#define Z80_LBUFSIZE 16 /* Uninteresting to the normal user */
#define Z80_HBUFSIZE 16
/* The size of the memory used for the cache.
It must be word-aligned! */
#define Z80_CACHESIZE ((2*Z80_MEMSIZE)+Z80_LBUFSIZE+Z80_HBUFSIZE)
/* The space needed for memory control flags */
#define Z80_FLAGMEMSIZE Z80_MEMSIZE
/* Memory write access control flags:
;Memory flag values (signed byte):
; -1 to -128 read-only
; 0 ok to write (no detection)
; 1 to 16 access counters 1 to 16
; 17 to 63 reserved
; 64 to 127 user exception
Call Z80_SetMemFlag (described below) to set these flags.
A zero flag marks ordinary RAM, and no detection is made.
A negative flag (use Z80_MEM_ROM) marks read-only memory. Attempts
to write are ignored.
A value in the range Z80_MEM_CNT to Z80_MEM_CNT+Z80_MEM_CNTNUM-1
corresponds to write a access counter from 0 to Z80_MEM_CNTNUM-1.
On each write access, the corresponding counter in the Z80_AccessCnt
array is incremented by one. If the corresponding flag in the
Z80_CntType array is zero, the value is written, otherwise the attempt
to write is ignored.
A value in the range Z80_MEM_USR to Z80_MEM_USR+Z80_MEM_USRNUM-1
corresponds to a user memory exception from 0 to Z80_MEM_USRNUM-1.
If the Z80_MemHandler pointer is nonzero (non-NULL), the routine it
points to is called with the following parameters:
d1 contains the exception number (word).
d2 contains the value (byte).
a1 contains the Z80 address (word).
a2 is scratch (address of user-def routine).
Changes to a1 and a2 have no effect. The handler must protect any other
registers it uses, and return the following values:
d1 zero (longword) if value should be written, nonzero if not.
d2 countains the value (byte).
The memory handler call is mostly intended for more complex cases of
write access detection than the simple counters can handle. Not many
details can be found out about the current Cpu status from the memory
handler, since it is called in mid-execution of an instruction, and only
the base pointer registers TableB, Z0, CacheB and FlagsB can be trusted
to have correct values. For a list of register aliases, see the file
Z80_coding.i.
Example in C:
Z80_SetMemFlag(Control, $4000, $1B00, Z80_MEM_CNT+5);
flags the area from $4000 to $5AFF as access counter 5.
Z80_CntType[5] = 1;
sets the type of counter 5 to 'do not write'.
(Remember: the range is from 0 to Z80_MEM_CNTNUM - 1.)
*/
#define Z80_MEM_ROM (-1)
#define Z80_MEM_CNT 1
#define Z80_MEM_CNTNUM 16
#define Z80_MEM_USR 64
#define Z80_MEM_USRNUM (128-Z80_MEM_USR)
struct Z80_Control {
LONG Workspace; /* temporary storage, byte swapping and so on */
ULONG AccessCnt[Z80_MEM_CNTNUM]; /* Memory write access counters */
#define Z80_BCDSTACKSIZE 7 /* BCD stack (must be word-aligned!) */
BYTE Z80_BCDstack[6*Z80_BCDSTACKSIZE];
BYTE CntType[Z80_MEM_CNTNUM];
/* Counter type designations. Zero for write,
nonzero for no write. */
UBYTE Parity[256]; /* Parity translation table */
/* Public: */
BYTE * Memory; /* Pointer to the Z80 address space memory */
WORD * Cachemem; /* Pointer to the cache memory */
/* Public: */
BYTE * Flagmem; /* Pointer to the flag memory */
void * MemHandler; /* Pointer to User Memory Exception Handler */
/* Public (read-only): */
BYTE * zero; /* Pointer to Z80 address 0. The (signed)
word-sized Z80 registers (like Z80_HL)
can be used as offsets from this base
to access the Z80 memory space. */
WORD * cachezero; /* Corresponds to Z80_zero in cache memory */
BYTE * flagzero; /* Corresponds to Z80_zero in flag memory */
/* Public (read-only): */
WORD Running; /* Nonzero if running, zero if not */
/* Private: */
WORD Request; /* Request pointer (offset from InstrBase) */
WORD ReqLvl; /* Priority level of current request */
UWORD alt_CCR; /* This is the internal F' in CCR format */
WORD BCD_SP; /* Stack pointer for the BCD stack */
/* Must be word-aligned here! */
/* The Cpu Status structure (public fields):
Fields storing a register have simply the register's name.
The alternative registers are referred to as alt_<register>.
<register> here is one of:
byte-valued A, B, C, D, E, H, L, F, I, R
word-valued HL, IX, IY, SP, PC
special IFF, INTMOD
Accessing HL will affect H and L and vice versa (HL is an 'alias').
Only the word-valued entries are guaranteed to also be word-aligned.
IFF and INTMOD are byte-sized, and should be interpreted as follows:
IFF Bit 7 holds IFF2. Bit 6 holds IFF1. Bits 5-0 are zero.
INTMOD The values in the range -1 to 1 correspond to interrupt
modes 0 to 2, respectively.
None of these entries should be written to (and rather not read either)
unless the emulator is stopped, since their contents are then undefined.
Most are never updated or read from except upon exiting and continuing.
*/
struct CpuStatus {
BYTE pad_d0_3, alt_A, pad_d0_1, A;
BYTE pad_d1_3, alt_B, pad_d1_1, B;
BYTE pad_d2_3, alt_C, pad_d2_1, C;
BYTE pad_d3_3, alt_D, pad_d3_1, D;
BYTE pad_d4_3, alt_E, pad_d4_1, E;
WORD pad_d5_u;
union {
WORD w; /* HL can be word-accessed as s.Cpu.HL.w */
struct {
BYTE H;
BYTE L;
} b; /* or byte accessed as s.Cpu.HL.b.H (or L) */
} HL;
WORD pad_a2_u;
WORD SP;
/* Private fields */
LONG pad_a3, pad_a4, pad_a5, pad_a6;
union {
WORD w; /* IX can be word-accessed as s.Cpu.IX.w */
struct {
BYTE H;
BYTE L;
} b; /* or byte accessed as s.Cpu.IX.b.H (or L) */
} IX;
union {
WORD w; /* IY can be word-accessed as s.Cpu.IY.w */
struct {
BYTE H;
BYTE L;
} b; /* or byte accessed as s.Cpu.IY.b.H (or L) */
} IY;
union {
WORD w; /* H'L' can be word-accessed as s.Cpu.alt_HL.w */
struct {
BYTE H;
BYTE L;
} b; /* or byte accessed as s.Cpu.alt_HL.b.H (or L) */
} alt_HL;
WORD PC; /* PC (written/read only at exit/continue) */
BYTE F; /* These flags are calculated upon exit. */
BYTE alt_F; /* During emulation, they are unused. */
BYTE IFF; /* IFF2 in bit 7, IFF1 in bit 6 */
BYTE INTMOD; /* Interruptmode (-1 to 1) = (modes 0 to 2) */
BYTE I;
BYTE R; /* Only bit 7 is valid. See "notes.txt" */
/* word aligned here */
/* These could be inspected. If nonzero, a request has been
received but not yet served. */
WORD INT_FF; /* INTreq status */
WORD NMI_FF; /* NMIreq status */
WORD RES_FF; /* RESETreq status */
WORD BCD_OP; /* BCD operation */
UWORD BCD_C; /* BCD carry, in bit 0 */
BYTE BCD_A; /* BCD destination */
BYTE BCD_B; /* BCD source */
} Cpu;
#ifdef Z80_ENVDATA
/* User environment data area. Should be word-aligned here. */
struct Z80_Envdata Envdata;
#endif
}; /* end of struct Z80_Control */
/* Function prototypes and descriptions */
int Z80_Init(struct Z80_Control *);
/* Before the emulator is started, the control structure must be
initialised by calling Z80_Init() with a pointer to the structure.
The fields Z80_Memory and Z80_Cachemem must be pointing to
allocated memory. If the memory write access checking feature is
used, the field Z80_Flagmem must also be set, and if Z80_MemHandler
is nonzero it is assumed to point to a user memory exception handler.
See memory flag definitions above for details.
The user environment data area is not changed. All other fields
are automatically initialised. The Cpu Status fields are set up as
after a reset.
The return value is nonzero if an error occurred, and zero
otherwise.
*/
int Z80_Coldstart(struct Z80_Control *);
/* The emulator is started 'from scratch' with a CPU reset through a
call to Z80_Coldstart. A pointer to a control structure must be
given, and the structure must be initialised (see Z80_Init above).
The return value is nonzero if an error occurred, and zero
otherwise.
*/
int Z80_Continue(struct Z80_Control *);
/* Continue as if nothing happened since last exit (unless the saved
processor status has been manipulated). A pointer to a control
structure must be given.
Changes to other fields than the Cpu status structure entries
are not recommended; calling Z80_Continue does not guarantee
that such changes have any effect (see Z80_NewSettings).
The return value is the same as for Z80_Coldstart.
*/
/* About reallocating memory:
Call Z80_Exitreq and make sure the emulator has stopped before
reallocating memory (remember to copy the old memory contents to the
new areas), then update the corresponding entries in the control
structure (Z80_Memory, Z80_Cachemem and Z80_Flagmem). Calling
Z80_NewSettings will then make sure that Z80_Continue will resume
the emulation from the new addresses.
The control structure can be moved whenever the emulator is not
running, without doing anything other than passing the new address
to Z80_Continue.
*/
int Z80_NewSettings(struct Z80_Control *);
/* This subroutine makes the emulator update the private fields of the
control structure when changes to any of the public fields have taken
place, for instance if the Z80_Memory field is changed. Do not call
this routine while the emulator is running.
The return value is nonzero if an error occurred, and zero
otherwise.
*/
void Z80_SetByte(struct Z80_Control *, UWORD addr, BYTE val);
void Z80_SetWordLH(struct Z80_Control *, UWORD addr, UWORD val);
BYTE Z80_GetByte(struct Z80_Control *, UWORD addr);
WORD Z80_GetWordLH(struct Z80_Control *, UWORD addr);
void Z80_SetBlock(struct Z80_Control *,
UWORD start_addr, ULONG size, BYTE val);
void Z80_ReadBlock(struct Z80_Control *,
void *buffer, UWORD start_addr, ULONG size);
void Z80_WriteBlock(struct Z80_Control *,
void *buffer, UWORD start_addr, ULONG size);
/* Routines to access the Z80 address space.
All need a pointer to the control structure and a word-sized Z80
address (for block functions this is the block start address).
Z80_SetByte is passed a byte value to be written. It returns
nothing.
Z80_SetWordLH is passed a (high-end first) word value to be written
and writes it low-end first. It returns nothing.
Z80_GetByte returns the byte value.
Z80_GetWordLH reads a (low-end first) word value and returns it
high-end first.
All block functions are passed the block size as an unsigned
longword. They return nothing.
Z80_SetBlock is also passed the byte value to be written.
Z80_ReadBlock and Z80_WriteBlock are passed the buffer address
(in the 680x0 address space) as a pointer to void.
All Z80 address arithmetic is word-sized. For instance, calling
Z80_SetWordLH(ctrl, 0xffff, 0x1234) will set address $ffff to $34
and address $0000 to $12. The block functions will also wrap at $ffff.
*/
void Z80_SetMemFlag(struct Z80_Control *,
UWORD start_addr, ULONG size, BYTE flag);
/* Sets memory flags.
Takes a pointer to a control structure, a (word-sized) Z80 address,
the block size (an unsigned longword) and the flag value (a byte) as
parameters. Nothing is returned. For ranges of flag values, see the
definition of memory write access control flags above.
*/
BYTE Z80_GetMemFlag(struct Z80_Control *, UWORD addr);
/* Returns the memory flag value for an address.
Takes a pointer to a control structure and a (word-sized) Z80
address as parameters. It returns a byte-sized flag. For ranges of
flag values, see the definition of memory write access control flags
above.
*/
/* The requests could be called from hardware interrupts, keypresses,
menus or whatever. They do not affect any registers (apart from CCR),
and return nothing.
They all need a pointer to the control structure.
The detection time is currently not guaranteed to be anything.
Hopefully, it is always finite. It shouldn't be more than a few
emulated Z80 instructions.
*/
void Z80_EXITreq(struct Z80_Control *);
/*
The emulation can only be interrupted between (Z80) instructions, as
with the Z80 processor interrupts (and presently only after *certain*
Z80 instructions). Therefore, stopping the emulator 'from the outside'
is just another request call.
*/
void Z80_INTreq(struct Z80_Control *);
/*
Emulates pulling the INT line low.
*/
void Z80_NMIreq(struct Z80_Control *);
/*
Emulates a Non-Maskable Interrupt. (Negative edge triggered
on a real Z80.)
*/
void Z80_RESETreq(struct Z80_Control *);
/*
Emulates pulling the RESET line low.
*/
#endif /* Z80.h */